from flask import Flask, render_template, request, jsonify, send_file
from datetime import datetime
import os
import socket
import json
import threading

app = Flask(__name__)

# 文件存储相关配置
UPLOAD_FOLDER = 'uploads'
CHAT_HISTORY_FILE = 'chat_history.json'
HISTORY_LOCK = threading.Lock()  # 用于文件读写同步

active_servers = set()  # 存储活跃的聊天服务器IP

# 添加用户活跃时间记录
ACTIVE_USERS = {}  # 存储用户活跃时间
ACTIVE_TIMEOUT = 300  # 5分钟超时

if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)

# 加载历史聊天记录
def load_chat_history():
    try:
        with HISTORY_LOCK:
            if os.path.exists(CHAT_HISTORY_FILE):
                with open(CHAT_HISTORY_FILE, 'r', encoding='utf-8') as f:
                    history = json.load(f)
                    return [Message.from_dict(msg) for msg in history]
    except Exception as e:
        print(f"加载聊天记录失败: {e}")
    return []

# 保存聊天记录
def save_chat_history(messages):
    try:
        with HISTORY_LOCK:
            with open(CHAT_HISTORY_FILE, 'w', encoding='utf-8') as f:
                history = [msg.__dict__ for msg in messages]
                json.dump(history, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"保存聊天记录失败: {e}")

class Message:
    def __init__(self, username, content, timestamp, is_file=False, filename=None, to_user=None):
        self.username = username
        self.content = content
        self.timestamp = timestamp
        self.is_file = is_file
        self.filename = filename
        self.to_user = to_user
        
    @classmethod
    def from_dict(cls, data):
        """从字典创建消息对象"""
        return cls(
            username=data.get('username'),
            content=data.get('content') or data.get('message'),  # 兼容两种键名
            timestamp=data.get('timestamp'),
            is_file=data.get('is_file', False),
            filename=data.get('filename'),
            to_user=data.get('to_user')
        )

    def to_dict(self):
        return {
            'username': self.username,
            'message': self.content,
            'timestamp': self.timestamp,
            'is_file': self.is_file,
            'filename': self.filename if self.is_file else None,
            'to_user': self.to_user
        }

# 初始化消息列表
messages = load_chat_history()

def get_client_ip():
    """获取客户端IP地址"""
    if request.environ.get('HTTP_X_FORWARDED_FOR'):
        return request.environ['HTTP_X_FORWARDED_FOR']
    return request.environ['REMOTE_ADDR']

def get_local_ip():
    """获取本机IP地址"""
    try:
        # 创建一个UDP套接字
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # 连接一个外部地址（不需要真实连接）
        s.connect(('8.8.8.8', 80))
        # 获取本机IP
        ip = s.getsockname()[0]
        s.close()
        return ip
    except Exception:
        return '127.0.0.1'

def broadcast_presence():
    """广播本机存在"""
    try:
        # 创建UDP广播套接字
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.bind(('', 0))
        
        # 发送广播消息
        message = b'CHAT_SERVER_ONLINE'
        sock.sendto(message, ('<broadcast>', 9811))
        sock.close()
    except Exception as e:
        print(f"广播错误: {e}")

def start_broadcast_listener():
    """启动广播监听器"""
    def listener():
        try:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            sock.bind(('', 9811))
            
            while True:
                try:
                    data, addr = sock.recvfrom(1024)
                    if data == b'CHAT_SERVER_ONLINE':
                        active_servers.add(addr[0])
                except Exception:
                    continue
        except Exception as e:
            print(f"监听错误: {e}")
    
    import threading
    listener_thread = threading.Thread(target=listener, daemon=True)
    listener_thread.start()

    # 定期清理不活跃的服务器
    def cleanup_servers():
        while True:
            try:
                for server in list(active_servers):
                    try:
                        socket.create_connection((server, 9810), timeout=1)
                    except:
                        active_servers.discard(server)
                import time
                time.sleep(30)  # 每30秒检查一次
            except Exception:
                continue
    
    cleanup_thread = threading.Thread(target=cleanup_servers, daemon=True)
    cleanup_thread.start()

    # 定期广播本机存在
    def periodic_broadcast():
        while True:
            try:
                broadcast_presence()
                import time
                time.sleep(10)  # 每10秒广播一次
            except Exception:
                continue
    
    broadcast_thread = threading.Thread(target=periodic_broadcast, daemon=True)
    broadcast_thread.start()

@app.route('/get_active_servers')
def get_active_servers():
    """获取活跃的聊天服务器列表"""
    # 确保本机IP也在列表中
    local_ip = get_local_ip()
    if local_ip != '127.0.0.1':
        active_servers.add(local_ip)
    return jsonify(list(active_servers))

@app.route('/')
def home():
    return render_template('chat.html')

@app.route('/get_messages')
def get_messages():
    username = request.args.get('username', '')
    page = int(request.args.get('page', 1))
    page_size = int(request.args.get('page_size', 50))
    
    # 过滤消息
    filtered_messages = [
        msg.to_dict() for msg in messages
        if not msg.to_user or  # 公共消息
           (msg.to_user and msg.to_user == username) or  # 发给自己的私信
           (msg.to_user and msg.username == username)  # 自己发送的私信
    ]
    
    # 计算分页
    start_idx = (page - 1) * page_size
    end_idx = start_idx + page_size
    total_pages = (len(filtered_messages) + page_size - 1) // page_size
    
    return jsonify({
        'messages': filtered_messages[start_idx:end_idx],
        'total_pages': total_pages,
        'current_page': page
    })

@app.route('/send_message', methods=['POST'])
def send_message():
    data = request.get_json()
    username = data.get('username')
    message_content = data.get('message')
    to_user = data.get('to_user')
    
    if not username:
        username = f"用户({get_client_ip()})"
    
    # 更新用户活跃时间
    ACTIVE_USERS[username] = datetime.now()
    
    # 验证私聊目标用户存在
    if to_user:
        user_exists = False
        for msg in messages[-100:]:  # 检查最近的消息
            if msg.username == to_user:
                user_exists = True
                break
        if not user_exists:
            return jsonify({'error': '目标用户不存在'}), 404
    
    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    new_message = Message(username, message_content, timestamp, to_user=to_user)
    messages.append(new_message)
    
    # 保存聊天记录
    save_chat_history(messages)
    return jsonify({'status': 'success'})

@app.route('/get_online_users')
def get_online_users():
    """获取在线用户列表"""
    current_time = datetime.now()
    
    # 更新当前用户的活跃时间
    username = request.args.get('username')
    if username:
        ACTIVE_USERS[username] = current_time

    # 清理超时用户
    timeout_users = []
    for user, last_active in ACTIVE_USERS.items():
        if (current_time - last_active).total_seconds() > ACTIVE_TIMEOUT:
            timeout_users.append(user)
    
    for user in timeout_users:
        ACTIVE_USERS.pop(user, None)

    # 获取最近活跃的用户
    active_users = list(ACTIVE_USERS.keys())
    
    # 如果用户列表为空，从最近的消息中获取用户
    if not active_users:
        recent_users = set()
        for msg in messages[-50:]:  # 只从最近50条消息中获取
            if msg.username:
                recent_users.add(msg.username)
        active_users = list(recent_users)

    return jsonify(active_users)

@app.route('/upload_file', methods=['POST'])
def upload_file():
    if 'file' not in request.files:
        return jsonify({'error': '没有文件被上传'})
    
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': '没有选择文件'})
    
    if file:
        filename = os.path.join(UPLOAD_FOLDER, file.filename)
        file.save(filename)
        
        username = request.form.get('username')
        if not username:
            username = f"用户({get_client_ip()})"
            
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        new_message = Message(
            username=username,
            content=f'上传了文件: {file.filename}',
            timestamp=timestamp,
            is_file=True,
            filename=file.filename
        )
        messages.append(new_message)
        save_chat_history(messages)
        
        return jsonify({'status': 'success', 'filename': file.filename})

@app.route('/download_file/<filename>')
def download_file(filename):
    try:
        return send_file(
            os.path.join(UPLOAD_FOLDER, filename),
            as_attachment=True
        )
    except Exception as e:
        return jsonify({'error': '文件下载失败'})

@app.route('/private_chat/<target_user>')
def private_chat(target_user):
    """进入私聊页面"""
    return render_template('private_chat.html', target_user=target_user)

@app.route('/get_private_messages/<target_user>')
def get_private_messages(target_user):
    """获取与特定用户的私聊消息"""
    username = request.args.get('username', '')
    if not username:
        return jsonify({'error': '未指定用户名'})
        
    page = int(request.args.get('page', 1))
    page_size = int(request.args.get('page_size', 50))
    
    # 过滤私聊消息：确保只获取两个用户之间的对话
    filtered_messages = [
        msg.to_dict() for msg in messages
        if (msg.to_user == target_user and msg.username == username) or
           (msg.to_user == username and msg.username == target_user)
    ]
    
    # 按时间倒序排序
    filtered_messages.reverse()
    
    # 计算分页
    start_idx = (page - 1) * page_size
    end_idx = start_idx + page_size
    total_pages = (len(filtered_messages) + page_size - 1) // page_size
    
    return jsonify({
        'messages': filtered_messages[start_idx:end_idx],
        'total_pages': total_pages,
        'current_page': page
    })

@app.route('/get_client_ip')
def get_client_ip_route():
    """获取客户端IP地址的路由"""
    return jsonify({'ip': get_client_ip()})

if __name__ == '__main__':
    try:
        # 启动服务器发现机制
        start_broadcast_listener()
        # 运行Flask应用
        app.run(host='0.0.0.0', port=9810, debug=True)
    except Exception as e:
        print(f"启动服务器时出错: {e}")
